Notion Calender, Notion API로 일정 알림 슬랙 연동하기 - 1편에서는 노션의 자동화 기능을 통한 일정 추가 알림을 적용했습니다.
이어서 이번 포스트에서는 본격적으로 Notion API를 통한 일정 관리 봇을 만들어 보겠습니다.
저는 작은 기능 하나 때문에 컴퓨팅 서버를 두는것을 선호 하지않기 때문에 간단한 서버리스 형태로 구성해보겠습니다.
저희는 '일정 시간마다 노션 캘린더를 조회하여 슬랙을 통해 알림을 받는다'를 목표로 잡고 시작하겠습니다.
람다 함수 배포와 위한 세팅을 진행해보겠습니다.
❗️사전에 mac을 기준으로 aws-cli 설치와 인증 설정이 되어 있어야 합니다! 해당 과정은 이미 되어있다고 가정하겠습니다.
역할 생성
notion-calendar-image-1.png
IAM - 역할 - 역할 생성 - AWS 서비스 선택
사용 사례 - Lambda 선택
권한 추가
notion-calendar-image-2.png
람다 함수에 액세스 하기 위한 2개의 정책을 추가하고 역할을 생성합니다.
$ mkdir notion-calendar-bot
$ cd notion-calendar-bot
# yarn
$ yarn init
# npm
$ npm init
# yarn
$ yarn add @notionhq/client @slack/webhook moment-timezone dotenv
# npm
$ npm install @notionhq/client @slack/webhook moment-timezone dotenv
// index.js
const moment_timezone = require('moment-timezone')
const { Client } = require("@notionhq/client")
const { sendSlackMessage } = require('./slack-webhook')
require('dotenv').config()
const NOTION_SECRET_KEY = process.env.NOTION_SECRET_KEY
const NOTION_DATABASE_ID = process.env.NOTION_EXAMPLE_DATABASE_ID
const notion = new Client({ auth: NOTION_SECRET_KEY });
// 당일 일정 쿼리
const getTodaySchedule = async () => {
const date = new Date();
const today = moment_timezone.tz(date, 'Asia/Seoul').format('YYYYMMDD');
const response = await notion.databases.query({
database_id: NOTION_DATABASE_ID,
filter: {
property: "날짜",
date: {
equals: today,
},
},
});
const todaySchedule = await Promise.all(response.results.map(async (result) => {
const tag = result.properties['태그'];
const date = result.properties['날짜'];
const type = tag.select.name;
const startDate = date.date.start;
const endDate = date.date.end;
// '참석자' properties에는 노션 캘린더에서 실제 사용하고 있는 타입명을 사용합니다.
const users = result.properties['참석자'].people.map((user) => user.name);
return { name: users.join(', '), type, startDate, endDate };
}));
return todaySchedule;
}
exports.handler = async (event) => {
const data = await getTodaySchedule();
if(data.length === 0) return;
await sendSlackMessage(data);
};
// 로컬에서 실행할 때 handler 함수 직접 호출
if (require.main === module) {
(async () => {
try {
await exports.handler({});
console.log('함수 실행 완료');
} catch (error) {
console.error('함수 실행 중 오류 발생:', error);
}
})();
}
///////////////////////////////////////////////////////////////////////////
// slack-bot.js
const { IncomingWebhook } = require('@slack/webhook');
require('dotenv').config();
const SLACK_URL = process.env.SLACK_URL;
const webhook = new IncomingWebhook(SLACK_URL);
const TAG = {
'연차': '🏝️ 연차',
'반차': '🏖️ 반차',
'반반차': '⛱️ 반반차',
'예비군': '🪖 예비군',
'병가': '😷 병가',
'출장': '🚌 출장',
'휴무': '🔴휴무',
// ...
// 캘린더 태그 타입에 맞는 키-라벨 매핑
}
const calculateDaysBetween = (start, end) => {
const startDate = new Date(start);
const endDate = new Date(end);
const timeDifference = endDate - startDate; // 밀리초 단위 차이
const daysDifference = timeDifference / (1000 * 3600 * 24) + 1; // 일 단위로 변환
return daysDifference;
}
async function sendSlackMessage(data) {
let userCount = data.length;
const formattedList = data.map(item => {
if(!TAG[item.type]) {
userCount = userCount - 1;
return;
};
let date = item.startDate;
const days = calculateDaysBetween(item.startDate, item.endDate);
if(item.endDate) {
date = `${date} ~ ${item.endDate}(${days}일)`;
}
return `- *${TAG[item.type]}* ${item.name} - ${date}`
}).join("\n");
if(userCount === 0) return;
await webhook.send(`*🗓️ 일정 알림 봇*\n\n${formattedList}`);
}
module.exports = { sendSlackMessage };
총 2개의 파일을 생성후 해당 코드를 추가합니다. 개인 상황에 맞게 충분히 수정하여 사용하시면 됩니다.
{
// ...
"scripts": {
"deploy:create": "zip -r function.zip . && aws lambda create-function --function-name schedule-bot --zip-file fileb://function.zip --region ap-northeast-2 --handler index.handler --runtime nodejs20.x --role arn:aws:iam::xxxxxxxxxxxx:role/xxxx",
"deploy": "zip -r function.zip . && aws lambda update-function-code --function-name schedule-bot --zip-file fileb://function.zip --region ap-northeast-2"
},
}
--function-name에는 원하는 람다 함수명을 추가합니다.
--role arn:aws:iam::xxxxxxxxxxxx:role/xxxx에는 AWS 계정 ID와 위에서 만들었던 역할의 키를 넣습니다.
# .env
# notion
NOTION_SECRET_KEY=
NOTION_EXAMPLE_DATABASE_ID=
# 슬랙 웹훅
SLACK_URL=
# AWS
AWS_SCHEDULE_ROLE=
위 역할 생성 과정까지 왔다면 이전에 구성해둔 서버 코드에서 람다 함수 배포 명령어를 실행합니다.
$ yarn deploy:create
이 스크립트는 기존에 작성한 모든 코드를 하나의 zip 파일로 압축하고 방금 만들어둔 IAM 역할으로 권한을 쥐고 람다 함수에 배포하기 위한 스크립트입니다.
❗️aws-cli와 인증이 설정되어 있지 않다면 정상 동작하지 않습니다.
❗️aws-cli의 프로필이 원하는 AWS 계정으로 지정되어 있지 않다면 한참을 헤매실 수 있습니다. 물론 저도 알고 싶지 않았습니다.
이렇게 배포를 성공하게 되면 람다 함수가 정상적으로 배포되어 있습니다.
이제는 마지막으로 초기에 설정했던 목표인 '일정 시간마다 슬랙 알림 발동'을 세팅해보겠습니다.
notion-calendar-image-3.png
Lambda - 함수 - schedule-bot - 트리거 추가 선택
notion-calendar-image-4.png
cron(10 0 * * ? *)
추가cron 표현식은 기본적으로 UTC 시간대를 사용합니다.
cron(10 0 * * ? *)
: UTC 기준 매일 00:10(자정)에 실행됩니다.저는 사내 요구사항에 따라 '매일 오전 9시 10분'에 이벤트를 실행하도록 이 크론식을 사용했습니다.
notion-calendar-image-5.png
저는 최종적으로 매일 오전 9시 10분에 노션 캘린더에 일정들을 슬랙으로 받을수 있게 되었습니다!
이런 형태로 각자의 요구사항과 맞게 코드단에서 조회 로직과 이벤트의 스케줄러 시간 등을 변경해서 충분히 커스텀하여 사용할 수 있습니다!
비용 효율을 따져 서버리스 형태로 구성하고, 입맛대로 코드를 적용해서 배포까지 경험할 수 있어서 재미 있었습니다. 초기 설계부터 서버와 자체적인 자원으로 인프라 구성까지 A-Z를 내 손으로 직접 구축하는게 개발자의 참맛이지 않나 싶습니다.
부족한 설명이 될 수 있지만 누군가에게 제 포스트가 도움이 되었으면 좋겠습니다! 👋
추가적인 도움이 필요하시면 언제든 제 이메일로 연락주시면 부족하지만 최대한 도움 드리겠습니다!